package com.ken.ability.gateway.auth.manager;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
 * Redis认证管理器 - 验证用户身份
 */
@Component
public class RedisAuthenticationManager implements ReactiveAuthenticationManager {

    @Autowired
    private TokenStore tokenStore;

    @Override
    public Mono<Authentication> authenticate(Authentication authentication) {
        return Mono.just(authentication)
                .filter(authen -> authen instanceof BearerTokenAuthenticationToken)
                .cast(BearerTokenAuthenticationToken.class)
                .map(BearerTokenAuthenticationToken::getToken)
                .flatMap(token -> {
                    //根据token获得Oauth2认证令牌
                    OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
                    if (oAuth2AccessToken == null) {
                        return Mono.error(new InvalidTokenException("令牌校验失败！"));
                    }

                    if (oAuth2AccessToken.isExpired()) {
                        return Mono.error(new InvalidTokenException("令牌已经过期！"));
                    }

                    //获得Oauth2Token认证对象
                    OAuth2Authentication oAuth2Authentication = tokenStore.readAuthentication(oAuth2AccessToken);
                    if (oAuth2AccessToken == null) {
                        return Mono.error(new InvalidTokenException("Access Token无效！"));
                    }
                    return Mono.just(oAuth2Authentication);
                });
    }
}
